package de.slowlog;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;

public class SlowLogReader {

	private final static String TIME_TOKEN = "# Time:";
	private final static String USER_HOST_TOKEN = "# User@Host:";
	private final static String QUERY_TOKEN = "# Query_time";

	private final static DateFormat dateFormat = new SimpleDateFormat(
			"yyMMdd HH:mm:ss");

	public SlowLog read(String filename) throws IOException, ParseException {
		BufferedReader reader = new BufferedReader(new FileReader(filename));
		SlowLog log = new SlowLog();

		String line = readToTimeToken(reader);
		if (line == null) {
			return log;
		}

		Date currentTime = parseTime(line);
		SlowLogEntry entry = null;

		line = reader.readLine();
		do {
			if (line == null) {
				break;
			}

			if (line.startsWith(TIME_TOKEN)) {
				currentTime = parseTime(line);
				line = reader.readLine();

			} else if (line.startsWith(USER_HOST_TOKEN)) {
				entry = new SlowLogEntry();
				entry.setTime(currentTime);

				line = parseEntry(line, reader, entry);

				log.addEntry(entry);
			}
		} while (true);

		return log;
	}

	private String parseEntry(String line, BufferedReader reader,
			SlowLogEntry entry) throws IOException {
		parseUserInfo(line, entry);

		line = reader.readLine();
		if (line.startsWith(QUERY_TOKEN)) {
			parseQueryInfo(line, entry);
		} else {
			throw new RuntimeException("expected " + QUERY_TOKEN);
		}

		line = parseQuery(line, reader, entry);

		return line;
	}

	private String readToTimeToken(BufferedReader reader) throws IOException {
		String line;
		while ((line = reader.readLine()) != null) {
			if (line.startsWith(TIME_TOKEN)) {
				return line;
			}
		}

		return null;
	}

	private Date parseTime(String line) throws ParseException {
		String datetime = line.substring(8);
		Date date = dateFormat.parse(datetime);

		return date;
	}

	private void parseUserInfo(String line, SlowLogEntry entry) {
		String user_host = line.substring(13);
		String[] split = user_host.split("@");

		entry.setUser(split[0].trim());
		entry.setHost(split[1].trim());
	}

	private void parseQueryInfo(String line, SlowLogEntry entry) {
		StringTokenizer st = new StringTokenizer(line);

		while (st.hasMoreTokens()) {
			String token = st.nextToken();
			if (token.equals("#")) {
				continue;
			}

			if (token.startsWith("Query_time")) {
				token = st.nextToken();
				double d = Double.parseDouble(token);
				entry.setQueryTime(d);
				continue;
			}

			if (token.startsWith("Lock_time")) {
				token = st.nextToken();
				double d = Double.parseDouble(token);
				entry.setLockTime(d);
				continue;
			}

			if (token.startsWith("Rows_sent")) {
				token = st.nextToken();
				int i = Integer.parseInt(token);
				entry.setRowsSent(i);
				continue;
			}

			if (token.startsWith("Rows_examined")) {
				token = st.nextToken();
				int i = Integer.parseInt(token);
				entry.setRowsExamined(i);
				continue;
			}
		}
	}

	private String parseQuery(String line, BufferedReader reader,
			SlowLogEntry entry) throws IOException {
		StringBuilder sb = new StringBuilder(line);

		while ((line = reader.readLine()) != null) {
			if (!line.startsWith("#")) {
				sb.append(line);
			} else {
				break;
			}
		}

		entry.setQuery(sb.toString());
		return line;
	}

	private class ParserState {
		BufferedReader reader;
		String line;
		boolean parsed;

		public ParserState(BufferedReader reader) {
			this.reader = reader;
		}

		public String nextLine() throws IOException {
			return line = reader.readLine();
		}

		public boolean parsed() {
			return parsed;
		}

		public void setParsed(boolean parsed) {
			this.parsed = parsed;
		}

	}

	public static void main(String[] args) throws IOException, ParseException {
		new SlowLogReader().read("mysql-slow.log");
	}
}
